using System.Net;
using System.Text;
using SuperSocket.Channel;
using SuperSocket.ProtoBase;

namespace SuperSocket.Client.Proxy;

internal sealed class HttpRequest : ProxyRequest<TextPackageInfo>
{
    private readonly string _username;
    private readonly string _password;

    private readonly string _httpHandshake;
    private readonly IChannel<TextPackageInfo> _channel;
    private readonly IAsyncEnumerator<TextPackageInfo> _packStream;
    private readonly Encoding _textEncoding = Encoding.ASCII;

    private const string RequestTemplate =
        "CONNECT {0}:{1} HTTP/1.1\r\nHost: {0}:{1}\r\nProxy-Connection: Keep-Alive\r\n";

    private const string ResponsePrefix = "HTTP/1.";
    private const string NewLine = "\r\n";

    public HttpRequest(IChannel<TextPackageInfo> channel,
        IAsyncEnumerator<TextPackageInfo> packStream,
        EndPoint remoteEndPoint,
        string username,
        string password)
    {
        _channel = channel;
        _packStream = packStream;
        _username = username;
        _password = password;
        if (remoteEndPoint is DnsEndPoint dnsEndPoint)
        {
            _httpHandshake = string.Format(RequestTemplate, dnsEndPoint.Host, dnsEndPoint.Port);
        }
        else if (remoteEndPoint is IPEndPoint ipEndPoint)
        {
            _httpHandshake = string.Format(RequestTemplate, ipEndPoint.Address, ipEndPoint.Port);
        }
        else
        {
            throw new Exception($"The endpint type {remoteEndPoint.GetType()} is not supported.");
        }
    }

    public override async ValueTask<TextPackageInfo> SendHandshakeAsync()
    {
        // send request
        await _channel.SendAsync((writer) =>
        {
            writer.Write(_httpHandshake, _textEncoding);

            if (!string.IsNullOrEmpty(_username) && !string.IsNullOrEmpty(_password))
            {
                writer.Write("Proxy-Authorization: Basic ", _textEncoding);
                writer.Write(Convert.ToBase64String(_textEncoding.GetBytes($"{_username}:{_password}")), _textEncoding);
                writer.Write(NewLine, _textEncoding);
                writer.Write(NewLine, _textEncoding);
            }
            else
            {
                writer.Write(NewLine, _textEncoding);
            }
        });

        return await _packStream.ReceiveAsync();
    }

    public override ValueTask<TextPackageInfo> SendAuthenticateAsync()
    {
        throw new NotImplementedException();
    }

    public override ValueTask<TextPackageInfo> SendEndPointAsync()
    {
        throw new NotImplementedException();
    }
}